#pragma once
#include <iostream>
#include <memory>
#include "Socket.hpp"
#include "InetAddr.hpp"
#include "Connection.hpp"
#include "IOService.hpp"
#include "Reactor.hpp"
#include "Protocol.hpp"
#include"Calclulator.hpp"

using namespace SocketModule;

// 使用继承的方式去实现不同模式
class Listener : public Connection
{
public:
    Listener(uint16_t port)
        : _listensock(std::make_unique<TcpSocket>()), _port(port)
    {
        _listensock->BuildTcpSocketMethod(port);
        // 直接创建出来一个TCP套接字了。这里默认就是ET模型，不过可以设置开启是ET还是LT模式，设置成define宏定义——预处理时直接展开代码，效率高，模式切换便捷。避免了，函数调用的栈帧创建和销毁带来效率损耗。
        SetSockfd(_listensock->Fd());
        SetEvents(EPOLLIN | EPOLLET);
    }
    virtual void Sender() override
    {
    }
    // 我们回调到这里，天然就有父类的Connection
    virtual void Recver() override
    {
        // 此时读就绪，是listensockfd就绪
        // 本质是IO处理---获取新链接
        // 你怎么知道，一次来的，就是一个链接呢？你怎么保证你一次读完了？
        // 上面就是我们要考虑的问题
        while (true)
        {
            InetAddr peer;
            int accepter_errno;
            // accept 非阻塞的时候，就是IO，我们就像处理read一样，处理accept没有区别。accept=阻塞+拷贝。而read就是在拷贝。
            int sockfd = _listensock->Accepter(&peer, &accepter_errno); // 这里期望把错误码带出来，然后分别处理不同的错误，因为errno在系统重只会记录最新一次的错误码，这里把错误码带出来也方便我们储存错误码从而查看错误。
            if (sockfd > 0)
            {
                // 成功
                // 成功了我就需要把这个链接fd交给Epoll模型，让Epoll去处理fd中的阻塞，读或写的阻塞。
                // epollserver只认Connection，这是我们做的封装。
                std::cout << "Accept 成功" << std::endl;
                // 这里就是处理普通的fd了，处理IO，在我看来也是Connection基类（含有缓冲区变量）
                // 1.设置文件描述符非阻塞,放在IOService里更好，分类更清晰
                //SetNonBlock(sockfd);

                // 2.sockfd包装成为Connection,才能插入到EpollServer
                auto conn = std::make_shared<IOService>(sockfd);
                conn->RegisterOnMessage(HandlerRequest);//添加协议回调处理函数。
                //3.插入到EpollServer
                GetOwner()->InsertConnetion(conn);
            }
            else
            {
                // 失败
                if (accepter_errno == EAGAIN || accepter_errno == EWOULDBLOCK)
                {
                    // 正常读取完了。
                    std::cout << "读完了" << std::endl;
                    break;
                }
                else if (accepter_errno == EINTR)
                {
                    // 函数调用被中断了。
                    std::cout << "被中断了" << std::endl;
                    continue;
                }
                else
                {
                    // 真正的失败
                    std::cout << "失败了" << std::endl;
                    break;
                }
            }
        }
    }
    virtual void Excepter() override
    {
    }

    int Sockfd()
    {
        return _listensock->Fd();
    }
    ~Listener()
    {
        _listensock->Close();
    }

private:
    std::unique_ptr<Socket> _listensock;
    uint16_t _port;
};

// vesion-1使用回调指针的方式去实现不同模式
//  class Listener
//  {
//  public:
//      Listener(int port)
//          : _listensock(std::make_unique<TcpSocket>()), _port(port)
//      {
//          _listensock->BuildTcpSocketMethod(port);
//          // 直接创建出来一个TCP套接字了。
//      }
//      // 获取新链接
//      void Accepter(std::shared_ptr<Connection> conn)
//      {
//          //此时读就绪，是listensockfd就绪
//          //本质是IO处理---获取新链接
//          //你怎么知道，一次来的，就是一个链接呢？你怎么保证你一次读完了？
//          //上面就是我们要考虑的问题
//          while(true)
//          {
//              InetAddr peer;
//              int accepter_errno;
//              //accept 非阻塞的时候，就是IO，我们就像处理read一样，处理accept没有区别。accept=阻塞+拷贝。而read就是在拷贝。
//              int sockfd = _listensock->Accepter(&peer,&accepter_errno);//这里期望把错误码带出来
//              if(sockfd>0)
//              {
//                  //成功
//                  //成功了我就需要把这个链接fd交给Epoll模型，让Epoll去处理fd中的阻塞，读或写的阻塞。
//                  //epollserver只认Connection，这是我们做的封装。
//                  auto conn=Factory::BuildConnection(sockfd,EPOLLIN | EPOLLET,nullptr,nullptr,nullptr);
//                  conn->SetPeerInfo(peer);
//                  conn->owner->InsertConnection();
//              }
//              else
//              {
//                  //失败
//                  if(accepter_errno == EAGAIN || accepter_errno == EWOULDBLOCK)
//                  {
//                      //正常读取完了。
//                      std::cout<<"读完了"<<std::endl;
//                      break;
//                  }
//                  else if(accepter_errno == EINTR)
//                  {
//                      //函数调用被中断了。
//                      std::cout<<"被中断了"<<std::endl;
//                      continue;
//                  }
//                  else{
//                      //真正的失败
//                      std::cout<<"失败了"<<std::endl;
//                      break;
//                  }
//              }
//          }
//      }
//      int Sockfd()
//      {
//          return _listensock->Fd();
//      }
//      ~Listener()
//      {
//          _listensock->Close();
//      }

// private:
//     std::unique_ptr<Socket> _listensock;
//     int _port;
// };